#include "memory.hpp"

extern std::map<uint64_t, Semaphore<std::array<char, 4096>>> memory;
const static int next[4] = {3, 2, 0, 1};

bool write(Cache &target, uint32_t tag, uint16_t count, uint16_t index, uint8_t size, uint8_t offset, uint64_t *MDR, Semaphore<MESIMeta> *message)
{
	uint64_t addr = tag;
	addr <<= (count == 512) ? 9 : 10; // 区分L1d和L2
	addr |= index;
	for (int i = 0; i < 4; i++)
	{
		if (std::get<2>(target.first[i]) == tag)
		{
			switch (std::get<1>(target.first[i]))
			{
			case M:
				memcpy(std::get<0>(target.first[i]).data() + offset, MDR, size);
				return true;
			case E:
				memcpy(std::get<0>(target.first[i]).data() + offset, MDR, size);
				std::get<1>(target.first[i]) = M;
				return true;
			case S:
				message->w_lock();
				message->get() = {I, addr};
				message->w_unlock();
				memcpy(std::get<0>(target.first[i]).data() + offset, MDR, size);
				std::get<1>(target.first[i]) = M;
				return true;
			case I:
				return false;
			}
		}
	}
	return false;
}
CacheLine *search(Cache &target, uint32_t tag)
{
	for (int i = 0; i < 4; i++)
	{
		if (std::get<2>(target.first[i]) == tag)
			if ((std::get<1>(target.first[i]) != I) && (std::get<1>(target.first[i]) != 0))
				return &target.first[i];
	}
	return nullptr;
}
void update(Cache &target, CacheLine &temp, uint32_t tag, uint64_t addr)
{
	int index = -1;
	for (int i = 0; i < 4; i++)
	{
		if ((std::get<1>(target.first[i]) & I) || (std::get<1>(target.first[i]) == 0)) // 查找无效的块
		{
			index = i;
			break;
		}
	}
	if (index == -1)
		index = target.second;
	if (memory.count(addr >> 12) == 0)
		memory[addr >> 12] = Semaphore<std::array<char, 4096>>();
	memory[addr >> 12].rlock();
	memcpy(std::get<0>(target.first[index]).data(), memory[addr >> 12].get().data() + (addr & 0xfc0), 64);
	memory[addr >> 12].r_unlock();
	std::get<1>(target.first[index]) = E;
	std::get<2>(target.first[index]) = tag;
	target.second = next[index];
}
void outChange(CacheLine &temp, uint16_t size)
{
	uint64_t addr = std::get<2>(temp);
	addr <<= 10; // 区分L1和L2
	addr |= size;
	addr <<= 6;
	memory[addr >> 12].w_lock();
	memcpy(memory[addr >> 12].get().data() + (addr & 0xfff), std::get<0>(temp).data(), 64);
	memory[addr >> 12].w_unlock();
}

MemCore::MemCore(MessageBus *pubVal, Semaphore<MESIMeta> *message)
{
	bus = pubVal;
	l1i = new std::array<CacheLine, 1024>;
	l1d = new std::array<Cache, 512>;
	l2 = new std::array<Cache, 1024>;
	this->message = message;
}
void MemCore::load()
{
	CacheLine *target = nullptr;
	uint32_t tag = 0;
	uint8_t offset = bus->MAR & 0x3f;
	uint16_t index = 0;
	if (bus->access & X) // 指令读取
	{
		index = (bus->MAR >> 6) & 0x3ff;
		tag = bus->MAR >> 16;
		if (std::get<2>((*l1i)[index]) != tag)
		{ // L1I未命中
		l1i_fail:
			target = search((*l2)[index], tag);
			if (target == nullptr)
			{ // L2未命中，读内存到L2当中，并交换到L1I
				CacheLine temp;
				update((*l2)[index], temp, tag, bus->MAR);
				if ((std::get<1>(temp) != 0) && (std::get<1>(temp) != I))
				{
					outChange(temp, 1024);
					message->w_lock();
					message->get() = {I, std::get<2>(temp)};
					message->w_unlock();
				}
				goto l1i_fail;
			}
			else
			{ // L2命中
				memcpy(&bus->MDR, std::get<0>(*target).data() + offset, bus->size);
				(*l1i)[index] = *target; // 交换L1I和L2的缓存行
			}
		}
		else if ((std::get<1>((*l1i)[index]) & I) || (std::get<1>((*l1i)[index]) == 0)) // L1I命中但为无效
			goto l1i_fail;
		else // L1I命中
			memcpy(&bus->MDR, std::get<0>((*l1i)[index]).data() + offset, bus->size);
	}
	else // 数据读取
	{
		index = (bus->MAR >> 6) & 0x1ff;
		tag = bus->MAR >> 15;
		target = search((*l1d)[index], tag);
		if (target == nullptr)
		{ // L1D未命中
		l1d_fail:
			index = (bus->MAR >> 6) & 0x3ff;
			tag = bus->MAR >> 16;
			target = search((*l2)[index], tag);
			if (target == nullptr)
			{ // L2未命中，读取到L2当中，并交换到L1D
				CacheLine temp;
				update((*l2)[index], temp, tag, bus->MAR);
				if ((std::get<1>(temp) != 0) && (std::get<1>(temp) != I))
				{
					outChange(temp, 1024);
					message->w_lock();
					message->get() = {I, std::get<2>(temp)};
					message->w_unlock();
				}
				goto l1d_fail;
			}
			else // L2命中
			{
				memcpy(&bus->MDR, std::get<0>(*target).data() + offset, bus->size);
				int ptr = (bus->MAR >> 6) & 0x1ff;
				int dest = (*l1d)[ptr].second;
				CacheLine *temp = (*l1d)[ptr].first + dest;
				if ((std::get<1>(*temp) == 0) || (std::get<1>(*temp) & I))
					*temp = *target;
				else
					std::swap((*l1d)[ptr].first[dest], *target); // 交换L1D和L2的缓存行
				(*l1d)[ptr].second = next[dest];				 // 更新L1D的PLRU指针
			}
		}
		else // L1D命中
			memcpy(&bus->MDR, std::get<0>(*target).data() + offset, bus->size);
	}
}
void MemCore::store()
{
	CacheLine *target = nullptr;
	uint64_t tag = 0, index = 0;
	uint8_t offset = bus->MAR & 0x3f;
dat_check:
	index = (bus->MAR >> 6) & 0x1ff;
	tag = bus->MAR >> 15;
	target = search((*l1d)[index], tag);
	if (target == nullptr)
	{ // L1D未命中
	l1d_fail:
		index = (bus->MAR >> 6) & 0x3ff;
		tag = bus->MAR >> 16;
		target = search((*l2)[index], tag);
		if (target == nullptr)
		{ // L2未命中，读取到L2当中，并交换到L1D
		l2d_fail:
			CacheLine temp;
			update((*l2)[index], temp, tag, bus->MAR);
			if ((std::get<1>(temp) != 0) && (std::get<1>(temp) != I))
			{
				message->w_lock();
				message->get() = {I, std::get<2>(temp)};
				message->w_unlock();
				outChange(temp, 1024);
			}
			goto dat_check;
		}
		else if (std::get<1>(*target) == I)
			goto l2d_fail;
		else
		// L2命中
		{
			write((*l2)[index], tag, 1024, index, bus->size, offset, &bus->MDR, message);
			int ptr = (bus->MAR >> 6) & 0x1ff;
			int dest = (*l1d)[ptr].second;
			std::swap((*l1d)[ptr].first[dest], *target); // 交换L1D和L2的缓存行
			(*l1d)[ptr].second = next[dest];			 // 更新L1D的PLRU指针
		}
	}
	else if ((std::get<1>(*target) == I) || (std::get<1>(*target) == 0))
		goto l1d_fail;
	else
		// L1D命中
		write((*l1d)[index], tag, 512, index, bus->size, offset, &bus->MDR, message);
}
void MemCore::change()
{
	message->rlock();
	uint64_t blockID = message->get().second;
	if (std::get<2>((*l1i)[blockID & 0x3ff]) == (blockID >> 10))
		std::get<1>((*l1i)[blockID & 0x3ff]) = message->get().first;
	CacheLine *target = search((*l1d)[blockID & 0x1ff], blockID >> 9);
	if (target != nullptr)
		std::get<1>(*target) = message->get().first;
	target = search((*l2)[blockID & 0x3ff], blockID >> 10);
	if (target != nullptr)
		std::get<1>(*target) = message->get().first;
	message->r_unlock();
}
void MemCore::shutdown()
{
	uint64_t blockID = 0;
	for (int i = 0; i < 512; i++)
	{
		for (int j = 0; j < 4; j++)
			if (std::get<1>((*l1d)[i].first[j]) & M)
			{
				blockID = std::get<2>((*l1d)[i].first[j]);
				blockID <<= 9;
				blockID |= i;
				memory[blockID >> 6].w_lock();
				memcpy(memory[blockID >> 6].get().data() + ((blockID << 6) & 0xfff), std::get<0>((*l1d)[i].first[j]).data(), 64);
				memory[blockID >> 6].w_unlock();
			}
	}
	for (int i = 0; i < 1024; i++)
	{
		for (int j = 0; j < 4; j++)
			if (std::get<1>((*l2)[i].first[j]) & M)
			{
				blockID = std::get<2>((*l2)[i].first[j]);
				blockID <<= 10;
				blockID |= i;
				memory[blockID >> 6].w_lock();
				memcpy(memory[blockID >> 6].get().data() + (blockID & 0xfff), std::get<0>((*l1d)[i].first[j]).data(), 64);
				memory[blockID >> 6].w_unlock();
			}
	}
}
void MemCore::run()
{
	while (bus->sregs[Status][bus->priv] ^ Halt)
	{
		change();
		bus->cMDR.lock();
		bus->tMAR.lock();
		if (bus->size == 0xffff) // 关机标志
		{
			shutdown();
			bus->needLoad.unlock(); // 通知处理器上层关机
			return;
		}
		if (bus->access & IO)
		{ // IO交给处理器上层操作
			bus->needLoad.unlock();
			bus->done.lock();
		}
		else if (bus->access & R)
			load();
		else if (bus->access & W)
			store();
		bus->dMDR.unlock();
		bus->dMAR.unlock();
	}
}